package cn.schoolwow.util.module.crypto.cipher.aes.flow;

import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.domain.check.instance.CheckInstance;
import cn.schoolwow.util.module.crypto.cipher.aes.domain.AESCipherOption;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Locale;

public class CheckAESCipherOption implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        AESCipherOption aesCipherOption = flowContext.checkInstanceData(AESCipherOption.class);

        CheckInstance.newCheck()
                .notEmptyCheck(aesCipherOption.secretKey, "AES算法加密密钥")
                .notEmptyCheck(aesCipherOption.data, "AES算法明文")
                .inValueCheck(Base64.getDecoder().decode(aesCipherOption.secretKey).length, Arrays.asList(
                        16,24,32
                ), "AES密钥长度");
        if(null!=aesCipherOption.mode){
            CheckInstance.newCheck()
                    .inValueCheck(aesCipherOption.mode.toUpperCase(Locale.ROOT), Arrays.asList(
                            "ECB","CBC","CFB","OFB","CTR","GCM"
                    ), "AES算法模式");
        }
        if(null!=aesCipherOption.padding){
            CheckInstance.newCheck()
                    .inValueCheck(aesCipherOption.padding, Arrays.asList(
                            "NoPadding","PKCS5Padding","PKCS7Padding"
                    ), "AES算法模式");
        }
        if(null!=aesCipherOption.iv){
            int ivLength = Base64.getDecoder().decode(aesCipherOption.iv).length;
            if(ivLength<16){
                throw new IllegalArgumentException("AES算法初始向量长度必须大于16字节!当前向量长度:"+ivLength);
            }
        }

        String instanceName = null==aesCipherOption.mode?"AES":"AES/"+aesCipherOption.mode+"/"+aesCipherOption.padding;
        Cipher cipher = Cipher.getInstance(instanceName);
        SecretKeySpec keySpec = new SecretKeySpec(aesCipherOption.secretKey.getBytes(StandardCharsets.UTF_8), "AES");
        flowContext.putTemporaryInstanceData(cipher, Cipher.class);
        flowContext.putTemporaryInstanceData(keySpec, SecretKeySpec.class);
    }

    @Override
    public String name() {
        return "检查AES算法选项";
    }
}
